package com.cblz.bd.database.spring.boot.starter.configure;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.update.Update;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * {@code @Name:} DataSecurityRestoreInnerInterceptor
 * {@code @Description: } 数据安全还原功能sql拦截器
 * {@code @Author:} by yanjieping
 * {@code @CreateDate:} 2022/12/27 - 周二
 */
@Slf4j
public class DataSecurityRestoreInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {


    /**
     * {@link StatementHandler#prepare(Connection, Integer)} 操作前置处理
     * <p>
     * 改改sql啥的
     *
     * @param sh                 StatementHandler(可能是代理对象)
     * @param connection         Connection
     * @param transactionTimeout transactionTimeout
     */
//    @Override
    @SneakyThrows
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler handler = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = handler.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        ParameterHandler parameterHandler = handler.parameterHandler();
        BoundSql boundSql = handler.boundSql();
        if (Objects.nonNull(boundSql.getParameterObject())) {
            // 识别传过来的参数是否带后缀 _DataSecurityRestoreSuffix ，带后缀则拦截，需要查询所有数据（包含逻辑删除）
            if (sct == SqlCommandType.SELECT && StringUtils.contains(boundSql.getParameterObject().toString(), "_DataSecurityRestoreSuffix")) {
                String parameter = boundSql.getParameterObject().toString();
                String replaceParameter = parameter.replaceAll("_DataSecurityRestoreSuffix", StringUtils.EMPTY);
                // 修改id的值
                boundSql.setAdditionalParameter("id", replaceParameter);
                // 修改sql
                PluginUtils.mpBoundSql(boundSql).sql(boundSql.getSql().replaceAll(" AND is_delete=0", StringUtils.EMPTY));
                parserMulti(boundSql.getSql(), boundSql.getParameterObject());
            }
            if (sct == SqlCommandType.UPDATE && StringUtils.contains(JSONUtil.toJsonStr(boundSql.getParameterObject()), "_DataSecurityRestoreSuffix")) {
                Map<String, Object> map = (Map) boundSql.getParameterObject();
                Map<String, Object> parameter1 = new HashMap<>();
                map.forEach((key, value) -> {
                    String removeRestoreSuffix = JSONUtil.toJsonStr(value).replace("_DataSecurityRestoreSuffix", StringUtils.EMPTY);
                    parameter1.put(key, JSONUtil.parseObj(removeRestoreSuffix));
                });
                Field boundSqlParameterObject = ReflectUtil.getField(boundSql.getClass(), "parameterObject");
                boundSqlParameterObject.setAccessible(true);
                boundSqlParameterObject.set(boundSql, parameter1);
                boundSql.setAdditionalParameter("_parameter", parameter1);

                Field parameterObject = ReflectUtil.getField(parameterHandler.getClass(), "parameterObject");
                parameterObject.setAccessible(true);
                parameterObject.set(parameterHandler, parameter1);
                // 修改sql
                String replaceAll = boundSql.getSql().replace("restoreIdentification = ?,", StringUtils.EMPTY).replace(" WHERE id=?  AND is_delete=0", ",is_delete=0 WHERE id=?  AND is_delete=1");
                PluginUtils.mpBoundSql(boundSql).sql(replaceAll);
                parserMulti(boundSql.getSql(), boundSql.getParameterObject());
            }
        }
    }

    /**
     * 更新
     *
     * @param update
     * @param index
     * @param sql
     * @param obj
     */
    @Override
    protected void processUpdate(Update update, int index, String sql, Object obj) {
        Expression where = update.getWhere();
        Assert.notNull(where, "非法SQL，必须要有where条件");
    }

    /**
     * 查询
     *
     * @param select
     * @param index
     * @param sql
     * @param obj
     */
    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
        Expression where = plainSelect.getWhere();
        Assert.notNull(where, "非法SQL，必须要有where条件");
    }

}
